using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Mbs.Collections;
using Mbs.ComponentModel.Container.Context;
using Mbs.Reflection;

namespace Mbs.ComponentModel.Container.Injection
{
    [Serializable]
    public abstract class MethodBaseInspect<TMethod> : InspectAdapter<TMethod> where TMethod : MethodBase
    {
       

        protected override IInjectContext<TMethod> DoExecute(IInspectContext ctx)
        {
            var type = ctx.Instance == null ? Component.Implementation : ctx.Instance.GetType();
            var methods = GetMethods(type);

            var ms = (from m in methods
                      let ps = m.GetParameters()
                      let att = m.GetAttribute<InjectAttribute>(false)
                      let ignoreAtt = m.GetAttribute<IgnoreInjectAttribute>(false)
                      where ignoreAtt == null
                            && MethodFilter(m)
                            && MethodAttributeFilter(att)
                            && ps.TrueForAll(p => Filter(p))
                      select new KeyValuePair<TMethod,string>(m,att.Id)
                       ).ToArray();

            return new InjectContext<TMethod>(ctx.Kernel, ctx.Component, ctx.Instance, ms);
        }

        protected virtual TMethod[] GetMethods(Type type) { return null; }

        protected virtual bool MethodAttributeFilter(InjectAttribute att)
        {
            return att != null;
        }

        protected virtual bool MethodFilter(TMethod method)
        {
            return true;
        }

        protected virtual bool Filter(ParameterInfo p)
        {
            var att = p.GetAttribute<InjectAttribute>(false);
            if (att != null && !string.IsNullOrEmpty(att.Id))
                return Kernel.HasRegister(att.Id);

            return Kernel.HasRegister(p.ParameterType);
        }
    }
}
